package com.enjoy.spring;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class EnjoyApplicationContext {

    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    private final Map<String, Object> singletons = new HashMap<>();

    public EnjoyApplicationContext(Class<?> configClass) throws ClassNotFoundException {
        scan(configClass);
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            Object bean = createBean(entry.getKey(), entry.getValue());
            singletons.put(entry.getKey(), bean);
        }
    }

    public void scan(Class<?> configClass) throws ClassNotFoundException {
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
            String value = componentScan.value();
            String path = Objects.requireNonNull(this.getClass().getResource("/")).getPath() + value.replace(".", "/");
            File file = new File(path);
            if (file.isDirectory()) {
                for (File listFile : Objects.requireNonNull(file.listFiles())) {
                    String filePath = listFile.getPath();
                    filePath = filePath.substring(filePath.indexOf("com"), filePath.indexOf(".class"));
                    String className = filePath.replace("\\", ".");
                    Class<?> aClass = Class.forName(className);
                    if (aClass.isAnnotationPresent(Component.class)) {
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(aClass);
                        Component annotation = aClass.getAnnotation(Component.class);
                        if (!"".equals(annotation.value())) {
                            beanDefinitionMap.put(annotation.value(), beanDefinition);
                        } else {
                            beanDefinitionMap.put(Introspector.decapitalize(aClass.getSimpleName()), beanDefinition);
                        }
                    }

                }
            }
        }
    }

    /**
     * 获取bean
     */
    public Object getBean(String beanName) {

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        Object o = singletons.get(beanName);
        if (o == null) {
            Object bean = createBean(beanName, beanDefinition);
            singletons.put(beanName, bean);
            return bean;
        }

        return o;
    }

    /**
     * 创建bean
     */
    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class<?> type = beanDefinition.getType();
        Object instance = null;

        try {
            instance = type.getConstructor().newInstance();
            for (Field field : type.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {

                    field.setAccessible(true);
                    Object bean = getBean(field.getName());
                    field.set(instance, bean);
                }
            }

            System.out.println("beanName = " + beanName);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                 NoSuchMethodException e) {
            e.printStackTrace();
        }

        return instance;
    }


}
